﻿using Architecture.CrossCutting.Common.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel.Channels;
using System.Text;
using System.Threading.Tasks;

namespace Architecture.CrossCutting.Web.WCF
{
    public class WcfServiceLog : BaseLog
    {

        public enum ServicePipelineStep
        {
            BeforeCall = 0,
            AfterCall = 1,
            BeforeSendReply = 2,
            AfterReceiveRequest = 3
        };

        public ServicePipelineStep Step { get; private set; }

        public String OperationName { get; private set; }

        public String Action { get; private set; }

        public DateTime PipeLineStarted { get; private set; }
        public DateTime PipeLineEnded { get; private set; }
        private Int64 PipeLineStartedTicks { get; set; }

        public Int64 PipeLineDuration { get; private set; }

        public Int64 SerializationDuration { get; private set; }

        public DateTime? OperationStarted { get; private set; }
        public DateTime? OperationEnded { get; private set; }
        public Int64 OperationDuration { get; private set; }
        private Int64 OperationStartedTicks { get; set; }

        public Int64 RequestLength { get; private set; }

        public Int64 ResponseLength { get; private set; }

        public Boolean IsFault { get; private set; }

        public WcfServiceLog() : base() { }


        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("CorrelationId : {0}", this.CorrelationId);
            sb.AppendLine();

            sb.AppendFormat("Step : {0}", this.Step);
            sb.AppendLine();

            sb.AppendFormat("Action : {0}", this.Action);
            sb.AppendLine();

            sb.AppendFormat("OperationName : {0}", this.OperationName);
            sb.AppendLine();

            sb.AppendFormat("PipeLineStarted : {0}", this.PipeLineStarted);
            sb.AppendLine();

            sb.AppendFormat("PipeLineEnded : {0}", this.PipeLineEnded);
            sb.AppendLine();

            sb.AppendFormat("PipeLineDuration : {0}", this.PipeLineDuration);
            sb.AppendLine();

            sb.AppendFormat("OperationEnded : {0}", this.OperationEnded);
            sb.AppendLine();

            sb.AppendFormat("RequestLength : {0}", this.RequestLength);
            sb.AppendLine();

            sb.AppendFormat("OperationStarted  : {0}", this.OperationStarted);
            sb.AppendLine();

            sb.AppendFormat("ResponseLength  : {0}", this.ResponseLength);
            sb.AppendLine();

            sb.AppendFormat("IsFault  : {0}", this.IsFault);
            sb.AppendLine();

            return sb.ToString();
        }


        public void RegisterRequest(Message request)
        {
            this.Action = request.Headers.Action;
            this.IsFault = false;
            this.RequestLength = request.ToString().Length;

            this.Step = WcfServiceLog.ServicePipelineStep.AfterReceiveRequest;
            this.PipeLineStarted = DateTime.UtcNow;
            this.PipeLineStartedTicks = Environment.TickCount;
        }

        public void RegisterResponse(Message reply)
        {
            this.Step = ServicePipelineStep.BeforeSendReply;
            this.PipeLineEnded = DateTime.UtcNow;
            this.PipeLineDuration = Environment.TickCount -this.PipeLineStartedTicks;
            this.ResponseLength = reply.ToString().Length;
            this.IsFault = reply.IsFault;
        }

        public void SetBeforeCallOperation(String operationName)
        {
            this.OperationName = operationName;
            this.Step = WcfServiceLog.ServicePipelineStep.BeforeCall;
            this.OperationStarted = DateTime.UtcNow;
            this.OperationStartedTicks = Environment.TickCount;
            this.SerializationDuration = Environment.TickCount - this.PipeLineStartedTicks;
        }

        public void SetAfterCallOperation()
        {
            this.Step = WcfServiceLog.ServicePipelineStep.AfterCall;
            this.OperationEnded = DateTime.UtcNow;
            this.OperationDuration = Environment.TickCount - this.OperationStartedTicks;
        }


    }
}
